home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Developers / src / out-of-phase-102-c / OutOfPhase 1.02 Source / OutOfPhase Folder / ASTConditional.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-23  |  10.5 KB  |  320 lines  |  [TEXT/KAHL]

  1. /* ASTConditional.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #include "ASTConditional.h"
  31. #include "ASTExpression.h"
  32. #include "TrashTracker.h"
  33. #include "Memory.h"
  34. #include "PromotableTypeCheck.h"
  35.  
  36.  
  37. struct ASTCondRec
  38.     {
  39.         ASTExpressionRec*        Conditional;
  40.         ASTExpressionRec*        Consequent;
  41.         ASTExpressionRec*        Alternate; /* may be NIL */
  42.         long                                LineNumber;
  43.     };
  44.  
  45.  
  46. /* create a new if node.  the Alternate can be NIL. */
  47. ASTCondRec*                    NewConditional(struct ASTExpressionRec* Conditional,
  48.                                             struct ASTExpressionRec* Consequent,
  49.                                             struct ASTExpressionRec* Alternate,
  50.                                             struct TrashTrackRec* TrashTracker, long LineNumber)
  51.     {
  52.         ASTCondRec*                MyCond;
  53.  
  54.         CheckPtrExistence(Conditional);
  55.         CheckPtrExistence(Consequent);
  56.         if (Alternate != NIL)
  57.             {
  58.                 CheckPtrExistence(Alternate);
  59.             }
  60.         CheckPtrExistence(TrashTracker);
  61.         MyCond = (ASTCondRec*)AllocTrackedBlock(sizeof(ASTCondRec),TrashTracker);
  62.         if (MyCond == NIL)
  63.             {
  64.                 return MyCond;
  65.             }
  66.         SetTag(MyCond,"ASTCondRec");
  67.  
  68.         MyCond->LineNumber = LineNumber;
  69.         MyCond->Conditional = Conditional;
  70.         MyCond->Consequent = Consequent;
  71.         MyCond->Alternate = Alternate;
  72.  
  73.         return MyCond;
  74.     }
  75.  
  76.  
  77. /* type check the conditional node.  this returns eCompileNoError if */
  78. /* everything is ok, and the appropriate type in *ResultingDataType. */
  79. CompileErrors                TypeCheckConditional(DataTypes* ResultingDataType,
  80.                                             ASTCondRec* Conditional, long* ErrorLineNumber,
  81.                                             struct TrashTrackRec* TrashTracker)
  82.     {
  83.         CompileErrors            Error;
  84.         DataTypes                    ConditionalReturnType;
  85.         DataTypes                    ConsequentReturnType;
  86.  
  87.         CheckPtrExistence(Conditional);
  88.         CheckPtrExistence(TrashTracker);
  89.  
  90.         Error = TypeCheckExpression(&ConditionalReturnType,Conditional->Conditional,
  91.             ErrorLineNumber,TrashTracker);
  92.         if (Error != eCompileNoError)
  93.             {
  94.                 return Error;
  95.             }
  96.         if (ConditionalReturnType != eBoolean)
  97.             {
  98.                 *ErrorLineNumber = Conditional->LineNumber;
  99.                 return eCompileConditionalMustBeBoolean;
  100.             }
  101.  
  102.         Error = TypeCheckExpression(&ConsequentReturnType,Conditional->Consequent,
  103.             ErrorLineNumber,TrashTracker);
  104.         if (Error != eCompileNoError)
  105.             {
  106.                 return Error;
  107.             }
  108.  
  109.         if (Conditional->Alternate == NIL)
  110.             {
  111.                 /* no else clause */
  112.                 *ResultingDataType = ConsequentReturnType;
  113.                 return eCompileNoError;
  114.             }
  115.          else
  116.             {
  117.                 DataTypes                    AlternateReturnType;
  118.  
  119.                 /* there is an else clause */
  120.                 Error = TypeCheckExpression(&AlternateReturnType,Conditional->Alternate,
  121.                     ErrorLineNumber,TrashTracker);
  122.                 if (Error != eCompileNoError)
  123.                     {
  124.                         return Error;
  125.                     }
  126.                 /* make sure the types can be promoted to each other */
  127.                 if (CanRightBeMadeToMatchLeft(ConsequentReturnType,AlternateReturnType))
  128.                     {
  129.                         if (MustRightBePromotedToLeft(ConsequentReturnType,AlternateReturnType))
  130.                             {
  131.                                 ASTExpressionRec*        PromotedThing;
  132.  
  133.                                 /* alternate must be promoted to be same as consequent */
  134.                                 PromotedThing = PromoteTheExpression(AlternateReturnType/*orig*/,
  135.                                     ConsequentReturnType/*desired*/,Conditional->Alternate,
  136.                                     Conditional->LineNumber,TrashTracker);
  137.                                 if (PromotedThing == NIL)
  138.                                     {
  139.                                         *ErrorLineNumber = Conditional->LineNumber;
  140.                                         return eCompileOutOfMemory;
  141.                                     }
  142.                                 Conditional->Alternate = PromotedThing;
  143.                                 /* sanity check */
  144.                                 Error = TypeCheckExpression(&AlternateReturnType/*obtain new type*/,
  145.                                     Conditional->Alternate,ErrorLineNumber,TrashTracker);
  146.                                 ERROR(Error != eCompileNoError,PRERR(ForceAbort,
  147.                                     "TypeCheckConditional:  type promotion caused failure"));
  148.                                 ERROR(ConsequentReturnType != AlternateReturnType,PRERR(ForceAbort,
  149.                                     "TypeCheckConditional:  after type promotion, types are no"
  150.                                     " longer the same"));
  151.                             }
  152.                     }
  153.                 else if (CanRightBeMadeToMatchLeft(AlternateReturnType,ConsequentReturnType))
  154.                     {
  155.                         if (MustRightBePromotedToLeft(AlternateReturnType,ConsequentReturnType))
  156.                             {
  157.                                 ASTExpressionRec*        PromotedThing;
  158.  
  159.                                 /* consequent must be promoted to be same as alternate */
  160.                                 PromotedThing = PromoteTheExpression(ConsequentReturnType/*orig*/,
  161.                                     AlternateReturnType/*desired*/,Conditional->Consequent,
  162.                                     Conditional->LineNumber,TrashTracker);
  163.                                 if (PromotedThing == NIL)
  164.                                     {
  165.                                         *ErrorLineNumber = Conditional->LineNumber;
  166.                                         return eCompileOutOfMemory;
  167.                                     }
  168.                                 Conditional->Consequent = PromotedThing;
  169.                                 /* sanity check */
  170.                                 Error = TypeCheckExpression(&ConsequentReturnType/*obtain new type*/,
  171.                                     Conditional->Consequent,ErrorLineNumber,TrashTracker);
  172.                                 ERROR(Error != eCompileNoError,PRERR(ForceAbort,
  173.                                     "TypeCheckConditional:  type promotion caused failure"));
  174.                                 ERROR(ConsequentReturnType != AlternateReturnType,PRERR(ForceAbort,
  175.                                     "TypeCheckConditional:  after type promotion, types are no"
  176.                                     " longer the same"));
  177.                             }
  178.                     }
  179.                 else
  180.                     {
  181.                         /* can't promote */
  182.                         *ErrorLineNumber = Conditional->LineNumber;
  183.                         return eCompileTypeMismatchBetweenThenAndElse;
  184.                     }
  185.                 ERROR(ConsequentReturnType != AlternateReturnType,PRERR(ForceAbort,
  186.                     "TypeCheckConditional:  Consequent and Alternate return types differ"));
  187.                 *ResultingDataType = ConsequentReturnType;
  188.                 return eCompileNoError;
  189.             }
  190.         EXECUTE(PRERR(ForceAbort,"TypeCheckConditional:  control reached end of function"));
  191.     }
  192.  
  193.  
  194. /* generate code for a conditional.  returns True if successful, or False if it fails. */
  195. MyBoolean                        CodeGenConditional(struct PcodeRec* FuncCode,
  196.                                             long* StackDepthParam, ASTCondRec* Conditional)
  197.     {
  198.         long                            StackDepth;
  199.         long                            PatchLocationForConditionalBranch;
  200.         long                            PatchForConditionalEnd;
  201.  
  202.         CheckPtrExistence(FuncCode);
  203.         CheckPtrExistence(Conditional);
  204.         StackDepth = *StackDepthParam;
  205.  
  206.         /* evaluate the condition */
  207.         if (!CodeGenExpression(FuncCode,&StackDepth,Conditional->Conditional))
  208.             {
  209.                 return False;
  210.             }
  211.         ERROR(StackDepth != *StackDepthParam + 1,PRERR(ForceAbort,
  212.             "CodeGenConditional:  stack bad after evaluating conditional"));
  213.  
  214.         /* perform branch to bad guy */
  215.         if (!AddPcodeInstruction(FuncCode,epBranchIfZero,&PatchLocationForConditionalBranch))
  216.             {
  217.                 return False;
  218.             }
  219.         if (!AddPcodeOperandInteger(FuncCode,-1/*not known yet*/))
  220.             {
  221.                 return False;
  222.             }
  223.         StackDepth -= 1;
  224.         ERROR(StackDepth != *StackDepthParam,PRERR(ForceAbort,
  225.             "CodeGenConditional:  stack bad after performing conditional branch"));
  226.  
  227.         /* evaluate the true branch */
  228.         if (!CodeGenExpression(FuncCode,&StackDepth,Conditional->Consequent))
  229.             {
  230.                 return False;
  231.             }
  232.         ERROR(StackDepth != *StackDepthParam + 1,PRERR(ForceAbort,
  233.             "CodeGenConditional:  stack bad after evaluating true branch"));
  234.         if (!AddPcodeInstruction(FuncCode,epBranchUnconditional,&PatchForConditionalEnd))
  235.             {
  236.                 return False;
  237.             }
  238.         if (!AddPcodeOperandInteger(FuncCode,-1/*not known yet*/))
  239.             {
  240.                 return False;
  241.             }
  242.  
  243.         StackDepth -= 1;
  244.  
  245.         /* patch the conditional branch */
  246.         ResolvePcodeBranch(FuncCode,PatchLocationForConditionalBranch,
  247.             PcodeGetNextAddress(FuncCode));
  248.  
  249.         /* evaluate the false branch */
  250.         if (Conditional->Alternate != NIL)
  251.             {
  252.                 /* there is a real live alternate */
  253.                 if (!CodeGenExpression(FuncCode,&StackDepth,Conditional->Alternate))
  254.                     {
  255.                         return False;
  256.                     }
  257.             }
  258.          else
  259.             {
  260.                 /* there is no alternate, so push zero or nil */
  261.                 switch (GetExpressionsResultantType(Conditional->Consequent))
  262.                     {
  263.                         default:
  264.                             EXECUTE(PRERR(ForceAbort,"CodeGenConditional:  bad type for 0"));
  265.                             break;
  266.                         case eBoolean:
  267.                         case eInteger:
  268.                         case eFixed:
  269.                             if (!AddPcodeInstruction(FuncCode,epLoadImmediateInteger,NIL))
  270.                                 {
  271.                                     return False;
  272.                                 }
  273.                             if (!AddPcodeOperandInteger(FuncCode,0))
  274.                                 {
  275.                                     return False;
  276.                                 }
  277.                             break;
  278.                         case eFloat:
  279.                             if (!AddPcodeInstruction(FuncCode,epLoadImmediateFloat,NIL))
  280.                                 {
  281.                                     return False;
  282.                                 }
  283.                             if (!AddPcodeOperandFloat(FuncCode,0))
  284.                                 {
  285.                                     return False;
  286.                                 }
  287.                             break;
  288.                         case eDouble:
  289.                             if (!AddPcodeInstruction(FuncCode,epLoadImmediateDouble,NIL))
  290.                                 {
  291.                                     return False;
  292.                                 }
  293.                             if (!AddPcodeOperandDouble(FuncCode,0))
  294.                                 {
  295.                                     return False;
  296.                                 }
  297.                             break;
  298.                         case eArrayOfBoolean:
  299.                         case eArrayOfInteger:
  300.                         case eArrayOfFloat:
  301.                         case eArrayOfDouble:
  302.                         case eArrayOfFixed:
  303.                             if (!AddPcodeInstruction(FuncCode,epLoadImmediateNILArray,NIL))
  304.                                 {
  305.                                     return False;
  306.                                 }
  307.                             break;
  308.                     }
  309.                 StackDepth += 1;
  310.             }
  311.         ERROR(StackDepth != *StackDepthParam + 1,PRERR(ForceAbort,
  312.             "CodeGenConditional:  stack depth bad after alternate"));
  313.  
  314.         /* resolve the then-skipover-else branch */
  315.         ResolvePcodeBranch(FuncCode,PatchForConditionalEnd,PcodeGetNextAddress(FuncCode));
  316.  
  317.         *StackDepthParam = StackDepth;
  318.         return True;
  319.     }
  320.